#include "lib_drm.h"

#include "mpp_buffer.h"


//****************************************************************************

#define CODEC_ALIGN(x, a)   (((x)+(a)-1)&~((a)-1))
#define rkdrm_log(fmt,...)\
            do {\
                printf(fmt,##__VA_ARGS__);\
            } while(0)


//****************************************************************************

struct sp_dev *mDev = NULL;
struct sp_plane **mPlanes;
struct sp_crtc *mCrtc;
struct sp_plane *mTestPlane;


//****************************************************************************

int rkdrm_init(void)
{
    int i, ret = 0;

    mDev = create_sp_dev();
    if (!mDev) {
        rkdrm_log("failed to exec create_sp_dev.\n");
        return -1;
    }

    ret = initialize_screens(mDev);
    if (ret != 0) {
        rkdrm_log("failed to exec initialize_screens.\n");
        return -2;
    }

    mPlanes = (struct sp_plane **)calloc(mDev->num_planes, sizeof(*mPlanes));
    if (!mPlanes) {
        rkdrm_log("failed to calloc mPlanes.\n");
        return -3;
    }

    mCrtc = &mDev->crtcs[0];
    for (i = 0; i < mCrtc->num_planes; i++) {
        mPlanes[i] = get_sp_plane(mDev, mCrtc);
        if (is_supported_format(mPlanes[i], DRM_FORMAT_NV12))
            mTestPlane = mPlanes[i];
    }

    if (!mTestPlane) {
        rkdrm_log("failed to get mTestPlane.\n");
        return -4;
    }

	log_e("mDev->crtcs[1].scanout=%x\n",mDev->crtcs[1].scanout);
	
	if(mDev->crtcs[1].scanout)
		fill_bo(mDev->crtcs[1].scanout, 0xFF, 0xFF, 0, 0);

    return 0;
}


int rkdrm_show_argb(uint32_t x, uint32_t y, uint32_t width,uint32_t height, uint8_t a, uint8_t r, uint8_t g, uint8_t b)
{
	struct sp_bo* bo = NULL;

	uint32_t i, j, xmax = x + width, ymax = y + height;

	if(!mDev->crtcs[1].scanout)
		return -1;

	bo = mDev->crtcs[1].scanout;

#if 0
	log_i("width  =%d\n",bo->width);
	log_i("height =%d\n",bo->height);
	log_i("pitch  =%d\n",bo->pitch);
#endif

    if (xmax > bo->width)
        xmax = bo->width;
    if (ymax > bo->height)
        ymax = bo->height;

	memset(bo->map_addr,0,bo->size);

    for (i = y; i < ymax; i++) {
        uint8_t* row = (uint8_t*)bo->map_addr + i * bo->pitch;

        for (j = x; j < xmax; j++) {
            uint8_t* pixel = row + j * 4;

            if (bo->format == DRM_FORMAT_ARGB8888 || bo->format == DRM_FORMAT_XRGB8888) {
                pixel[0] = b;
                pixel[1] = g;
                pixel[2] = r;
                pixel[3] = a;
            } else if (bo->format == DRM_FORMAT_RGBA8888) {
                pixel[0] = r;
                pixel[1] = g;
                pixel[2] = b;
                pixel[3] = a;
            }
        }
    }

	return 0;
}


int rkdrm_show_buff_0(uint32_t x, uint32_t y, uint32_t width,uint32_t height, const char *buff)
{
   struct sp_bo* bo = NULL;

   uint8_t a = 0;
   uint8_t r = 0;
   uint8_t g = 0;
   uint8_t b = 0;

   uint8_t* pixel = NULL;

   uint32_t i, j, xmax = x + width, ymax = y + height;


   if(!mDev->crtcs[0].scanout)
	   return -1;

   bo = mDev->crtcs[0].scanout;


#if 1
   if (xmax > bo->width)
	   xmax = bo->width;
   if (ymax > bo->height)
	   ymax = bo->height;
#endif

	for(i=0;i<1080;i++)
	{
		uint8_t* row = (uint8_t*)bo->map_addr + i * bo->pitch;

		for(j=0;j<1920;j++)
		{
			if((i >= y)&&(i < (y + height))&&(j >= x)&&(j < (x + width)))
			{
				pixel = row + j * 4;
				
				r = (*(buff + 0))&0x000000ff;
				g = (*(buff + 1))&0x000000ff;
				b = (*(buff + 2))&0x000000ff; 
						
				buff = buff + 3;
				
				if (bo->format == DRM_FORMAT_ARGB8888 || bo->format == DRM_FORMAT_XRGB8888) {
					pixel[0] = b;
					pixel[1] = g;
					pixel[2] = r;
					pixel[3] = a;
				} else if (bo->format == DRM_FORMAT_RGBA8888) {
					pixel[0] = r;
					pixel[1] = g;
					pixel[2] = b;
					pixel[3] = a;
				}
			}
			else
			{
				pixel = row + j * 4;

				r = 0x00;
				g = 0x00;
				b = 0x00; 

				pixel[0] = r;
				pixel[1] = g;
				pixel[2] = b;
				pixel[3] = a;

			}
		}
	}

   return 0;
}


int rkdrm_show_buff_1(uint32_t x, uint32_t y, uint32_t width,uint32_t height, const char *buff)
{
   struct sp_bo* bo = NULL;

   uint8_t a = 0;
   uint8_t r = 0;
   uint8_t g = 0;
   uint8_t b = 0;

   uint8_t* pixel = NULL;

   uint32_t i, j, xmax = x + width, ymax = y + height;


   if(!mDev->crtcs[1].scanout)
	   return -1;

   bo = mDev->crtcs[1].scanout;

#if 0
   log_i("width  =%d\n",bo->width);
   log_i("height =%d\n",bo->height);
   log_i("pitch  =%d\n",bo->pitch);
   log_i("size   =%d\n",bo->size);
#endif

#if 1
   if (xmax > bo->width)
	   xmax = bo->width;
   if (ymax > bo->height)
	   ymax = bo->height;
#endif

#if 0
   memset(bo->map_addr,0,bo->size);

   for (i = y; i < ymax; i++) {
	   uint8_t* row = (uint8_t*)bo->map_addr + i * bo->pitch;

	   for (j = x; j < xmax; j++) {
		   uint8_t* pixel = row + j * 4;

		   r = (*(buff + 0))&0x000000ff;
		   g = (*(buff + 1))&0x000000ff;
		   b = (*(buff + 2))&0x000000ff; 
		   		   
		   buff = buff + 3;

		   if (bo->format == DRM_FORMAT_ARGB8888 || bo->format == DRM_FORMAT_XRGB8888) {
			   pixel[0] = b;
			   pixel[1] = g;
			   pixel[2] = r;
			   pixel[3] = a;
		   } else if (bo->format == DRM_FORMAT_RGBA8888) {
			   pixel[0] = r;
			   pixel[1] = g;
			   pixel[2] = b;
			   pixel[3] = a;
		   }
	   }
   }
#elif 1

	for(i=0;i<1080;i++)
	{
		uint8_t* row = (uint8_t*)bo->map_addr + i * bo->pitch;

		for(j=0;j<1920;j++)
		{
			if((i >= y)&&(i < (y + height))&&(j >= x)&&(j < (x + width)))
			{
				pixel = row + j * 4;
				
				r = (*(buff + 0))&0x000000ff;
				g = (*(buff + 1))&0x000000ff;
				b = (*(buff + 2))&0x000000ff; 
						
				buff = buff + 3;
				
				if (bo->format == DRM_FORMAT_ARGB8888 || bo->format == DRM_FORMAT_XRGB8888) {
					pixel[0] = b;
					pixel[1] = g;
					pixel[2] = r;
					pixel[3] = a;
				} else if (bo->format == DRM_FORMAT_RGBA8888) {
					pixel[0] = r;
					pixel[1] = g;
					pixel[2] = b;
					pixel[3] = a;
				}
			}
			else
			{
				pixel = row + j * 4;

				r = 0x00;
				g = 0x00;
				b = 0x00; 

				pixel[0] = r;
				pixel[1] = g;
				pixel[2] = b;
				pixel[3] = a;

			}
		}
	}
#elif 1

	for(i=0;i<1080;i++)
	{
		uint8_t* row = (uint8_t*)bo->map_addr + i * bo->pitch;

		for(j=0;j<1920;j++)
		{
			pixel = row + j*4;
			
			r = 0x00;
			g = 0xff;
			b = 0x00; 
			
			pixel[0] = r;
			pixel[1] = g;
			pixel[2] = b;
			pixel[3] = a;
		}
	}
#elif 0

	memset(bo->map_addr,0xa5,bo->size);

#endif
   return 0;
}


void * rkdrm_get_map_addr(void)
{
	struct sp_bo* bo = NULL;

	if(!mDev->crtcs[1].scanout)
	   return NULL;

	bo = mDev->crtcs[1].scanout;

	return bo->map_addr;
}

uint32_t rkdrm_get_buff_width(void)
{
	struct sp_bo* bo = NULL;

	if(!mDev->crtcs[1].scanout)
	   return NULL;

	bo = mDev->crtcs[1].scanout;

	return bo->width;
}			   

int rkdrm_display(MppFrame frame)
{
    int x,y,w,h;
	struct sp_bo *bo;
    uint32_t handles[4], pitches[4], offsets[4];
    int width, height;
    int /*frm_size, */ret, fd, err;

    err = mpp_frame_get_errinfo(frame) |
          mpp_frame_get_discard(frame);
    if (err) {
        rkdrm_log("get err info %d discard %d, go back.\n",
                mpp_frame_get_errinfo(frame),
                mpp_frame_get_discard(frame));
        return -1;
    }

    width = mpp_frame_get_width(frame);
    height = mpp_frame_get_height(frame);
    width = CODEC_ALIGN(width, 16);
    height = CODEC_ALIGN(height, 16);
    //frm_size = width * height * 3 / 2;
    fd = mpp_buffer_get_fd(mpp_frame_get_buffer(frame));

    bo = (struct sp_bo *)calloc(1, sizeof(struct sp_bo));
    if (!bo) {
        rkdrm_log("failed to calloc bo.\n");
        return -2;
    }

    drmPrimeFDToHandle(mDev->fd, fd, &bo->handle);
    bo->dev = mDev;
    bo->width = width;
    bo->height = height;
    bo->depth = 16;
    bo->bpp = 32;
    bo->format = DRM_FORMAT_NV12;
    bo->flags = 0;

    handles[0] = bo->handle;
    pitches[0] = width;
    offsets[0] = 0;
    handles[1] = bo->handle;
    pitches[1] = width;
    offsets[1] = width * height;
    ret = drmModeAddFB2(mDev->fd, bo->width, bo->height,
                        bo->format, handles, pitches, offsets,
                        &bo->fb_id, bo->flags);
    if (ret != 0) {
        rkdrm_log("failed to exec drmModeAddFb2.\n");
        return -3;
    }

#if 1
	if(ffmpeg_get_video_w() > ffmpeg_get_video_h())
	{
		w = 1920;
		h = ffmpeg_get_video_h()*1920/ffmpeg_get_video_w();
		if(h > LCD_H)
		{
			h = LCD_H;
			w = ffmpeg_get_video_w()*h/ffmpeg_get_video_h();
		}
		
		x = (1920 - w)/2;
		y = (1080 - h)/2;
	}
	else
	{

		h = 1080;
		w = ffmpeg_get_video_w()*1080/ffmpeg_get_video_h();
		if(w > LCD_W)
		{
			w = LCD_W;
			h = ffmpeg_get_video_h()*w/ffmpeg_get_video_w();
		}

				
		x = (1920 - w)/2;
		y = (1080 - h)/2;
	}
#elif 0	
	if(ffmpeg_get_video_w() > LCD_W)
	{
		w = LCD_W;
	}

	if(ffmpeg_get_video_h() > LCD_H)
	{
		h = LCD_H;
	}

	w = ffmpeg_get_video_w();
	h = ffmpeg_get_video_h();		
	x = (1920 - w)/2;
	y = (1080 - h)/2;

#elif 0
	w = ffmpeg_get_video_w();
	h = ffmpeg_get_video_h();		
	x = (1920 - w)/2;
	y = (1080 - h)/2;
#elif 1

	w = ffmpeg_get_video_w();
	h = ffmpeg_get_video_h();		
	x = 0;
	y = 0;

#endif


    ret = drmModeSetPlane(mDev->fd, mTestPlane->plane->plane_id,
                          mCrtc->crtc->crtc_id, bo->fb_id, 0,
                          x, y,   // display x, y
                          w, 	  //1920,//mCrtc->crtc->mode.hdisplay, // display width
                          h,      // 1080,//mCrtc->crtc->mode.vdisplay, // display height
                          0, 0, bo->width << 16, bo->height << 16);
    if (ret) {
        rkdrm_log("failed to exec drmModeSetPlane.\n");
        return -3;
    }

    if (mTestPlane->bo) {
        if (mTestPlane->bo->fb_id) {
            ret = drmModeRmFB(mDev->fd, mTestPlane->bo->fb_id);
            if (ret)
                rkdrm_log("failed to exec drmModeRmFB.\n");
        }
        if (mTestPlane->bo->handle) {
            struct drm_gem_close req = {
                    .handle = mTestPlane->bo->handle,
            };

            drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_CLOSE, &req);
        }
        free(mTestPlane->bo);
    }
    mTestPlane->bo = bo;

    return 0;
}

int rkdrm_fini(void)
{
    if (mDev) destroy_sp_dev(mDev);
    if (mPlanes) free(mPlanes);
}
